package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
	"sync"
)

var ch chan string
var wg sync.WaitGroup

var defaultAssetPath = "static/assets" // 默认资源路径
var cdnAssetPath = "internalapi/asset" // cdn资源路径

// 目录
var dirPaths = []string{
	defaultAssetPath,
	cdnAssetPath,
}

// 域名
var domains = map[string]string{
	"default": "https://scratch.mit.edu/",
	"cdn":     "https://cdn.assets.scratch.mit.edu/",
}

func main() {
	// 1、解析js文件
	fmt.Println("parse js start...")
	data, err := parseJs()
	if err != nil {
		fmt.Println("parse js err: ", err)
		return
	}

	if len(data) == 0 {
		fmt.Println("none")
		return
	}
	fmt.Println("parse js end...")

	// 2、创建目录
	fmt.Println("create dir start...")
	createDir(dirPaths)
	fmt.Println("create dir end...")

	// 3、下载
	fmt.Println("download start...")
	download(data)
	fmt.Println("download end...")
}

// 解析js文件中的图片/音频等资源链接
func parseJs() ([]string, error) {
	filename := "js/projects.bundle.js"
	f, err := os.Open(filename)
	if err != nil {
		fmt.Println("file open err: ", err)
		return nil, err
	}
	defer f.Close()

	b, _ := io.ReadAll(f)
	s := string(b)

	// static/assets/talking-3-say-something.en.8e5a33f8b13b50ff97fd.png
	ruleAssets := `(static\/assets\/[a-zA-Z0-9\.\-_]+\.[a-z]+)`
	regAssets := regexp.MustCompile(ruleAssets)
	resAssets := regAssets.FindAllStringSubmatch(s, -1)

	// md5ext:"cd21514d0531fdffb22204e0ec5ed84a.svg"
	ruleMd5 := `"md5ext":"([a-z0-9]+\.[a-z0-9]+)"`
	regMd5 := regexp.MustCompile(ruleMd5)
	resMd5 := regMd5.FindAllStringSubmatch(s, -1)

	m := make(map[string]bool) // 去重
	data := make([]string, 0)  // url链接

	for _, v := range resAssets {
		if _, ok := m[v[1]]; !ok {
			m[v[1]] = true
			data = append(data, v[1])
		}
	}

	for _, v := range resMd5 {
		if _, ok := m[v[1]]; !ok {
			m[v[1]] = true
			data = append(data, fmt.Sprintf("%s/%s", cdnAssetPath, v[1]))
		}
	}

	// fmt.Println(data)
	// fmt.Println(len(m))
	// fmt.Println(len(data)) // 未去重2661;去重1331
	m = nil
	resAssets = nil
	resMd5 = nil

	return data, nil
}

// 创建目录
func createDir(data []string) {
	for _, v := range data {
		err := os.MkdirAll(v, 0666)
		if err != nil {
			panic(fmt.Sprintln("create dir err: ", err))
		}
	}
}

// 下载
func download(data []string) {
	taskNum := 20
	ch = make(chan string, 5)

	for i := 0; i < taskNum; i++ {
		go task(ch)
	}

	for _, v := range data {
		ch <- v
		wg.Add(1)
	}

	wg.Wait()
}

// 任务
func task(data chan string) {
	for {
		select {
		case msg := <-data:
			work(msg)
			wg.Done()
		}
	}
}

// 下载文件
func work(filename string) {
	// 设置代理
	tr := &http.Transport{
		Proxy: http.ProxyURL(&url.URL{
			Scheme: "http",
			Host:   "127.0.0.1:7890",
		}),
	}
	client := &http.Client{
		Transport: tr,
	}

	// 发起http的get请求
	link := ""
	if strings.HasPrefix(filename, cdnAssetPath) {
		link = fmt.Sprintf("%s%s/get", domains["cdn"], filename)
	} else {
		link = fmt.Sprintf("%s%s", domains["default"], filename)
	}
	resp, err := client.Get(link)

	if err != nil {
		fmt.Println("http request err: ", err)
		return
	}
	defer resp.Body.Close()

	// 读取内容
	b, err := io.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("read body err: ", err)
		return
	}

	// 写入文件
	err = os.WriteFile(filename, b, 0666)
	if err != nil {
		fmt.Println("write file err: ", err)
	}
}
